<!-- 应用生成对话页 -->
<template>
	<div id="app-chat-view">
		<!-- 顶部栏 -->
		<div class="header-bar">
			<div class="header-left">
				<a-button type="text" @click="goBack" class="back-btn">
					<template #icon>
						<ArrowLeftOutlined />
					</template>
					返回
				</a-button>
				<img class="header-logo" src="/favicon.ico" alt="logo" />
				<h1 class="app-name">{{ appInfo?.appName || '生成应用' }}</h1>
				<a-tag v-if="appInfo?.codeGenType" :color="getCodeGenTypeColor(appInfo.codeGenType)" class="code-gen-type-tag">
					{{ getCodeGenTypeText(appInfo.codeGenType) }}
				</a-tag>
			</div>
			<div class="header-right">
				<a-button @click="showAppDetailModal" :disabled="generating" :loading="generating" class="detail-btn">
					<template #icon>
						<InfoCircleOutlined />
					</template>
					{{ generating ? '生成中...' : '应用详情' }}
				</a-button>
				<a-button
					@click="downloadCode"
					:loading="downloading || generating"
					:disabled="!canDownload || generating"
					class="download-btn"
				>
					<template #icon>
						<DownloadOutlined />
					</template>
					{{ generating ? '生成中...' : '下载代码' }}
				</a-button>
				<a-button
					type="primary"
					@click="deployApp"
					:loading="deploying || generating"
					:disabled="!canDeployApp || generating"
					class="deploy-btn"
				>
					<template #icon>
						<RocketOutlined />
					</template>
					{{ generating ? '生成中...' : isDeployed ? '重新部署' : '部署应用' }}
				</a-button>
			</div>
		</div>

		<!-- 核心内容区域 -->
		<div class="content-area">
			<!-- 左侧对话区域 -->
			<div class="chat-section">
				<!-- 消息区域 -->
				<MessageList
					:messages="messages"
					:generating="generating"
					:has-more-history="hasMoreHistory"
					:loading-history="loadingHistory"
					:auto-scroll-enabled="autoScrollEnabled"
					:user-avatar="loginUserStore.loginUser?.userAvatar"
					:user-name="loginUserStore.loginUser?.userName"
					@load-more-history="loadMoreHistory"
					@scroll="handleScroll"
					@scroll-to-bottom="scrollToBottomManually"
					ref="messageListRef"
				/>

				<!-- 用户消息输入框 -->
				<ChatInput
					v-model="currentMessage"
					:can-edit="canEdit"
					:preview-url="previewUrl"
					:is-edit-mode="isEditMode"
					:generating="generating"
					:selected-elements="selectedElements"
					:messages="messages"
					:export-loading="exportLoading"
					:is-admin="isAdmin"
					@send="sendMessage"
					@stop="stopGeneration"
					@toggle-edit-mode="toggleEditMode"
					@export-chat-history="exportChatHistory"
					@remove-selected-element="removeSelectedElement"
					@clear-selected-elements="clearSelectedElements"
					@element-hover="handleElementHover"
				/>
			</div>

			<!-- 右侧网页展示区域 -->
			<div class="preview-section">
				<div class="preview-header">
					<h3>网页预览</h3>
					<div class="preview-actions" v-if="previewUrl">
						<a-button @click="refreshPreview">
							<template #icon>
								<ReloadOutlined />
							</template>
							刷新
						</a-button>
						<a-button @click="openInNewWindow">
							<template #icon>
								<ExportOutlined />
							</template>
							新窗口打开
						</a-button>
					</div>
				</div>
				<div class="preview-content">
					<!-- AI 生成中的加载效果 -->
					<div v-if="generating || showPreviewLoading" class="ai-loading-overlay">
						<div class="loading-content">
							<img :src="kunkunImg" alt="Loading" class="loading-kunkun" />
							<div class="loading-text">{{ generating ? '正在疯狂加班码字中 ...' : '正在加载预览 ...' }}</div>
						</div>
					</div>
					<!-- iframe预览区域 -->
					<iframe
						v-else-if="previewUrl && !previewError"
						ref="previewIframe"
						:src="previewUrl"
						class="preview-iframe"
						@load="onIframeLoad"
						@error="onIframeError"
					></iframe>

					<!-- 预览错误状态（统一处理所有错误情况） -->
					<div v-else-if="previewError" class="preview-error">
						<div class="error-content">
							<img :src="sadKunkunImg" alt="Preview Failed" class="error-kunkun" />
							<h4>哎呀，预览访问失败了</h4>
							<p>网页内容可能正在加载中，或者访问链接暂时无效</p>
							<div class="error-actions">
								<a-button @click="refreshPreview" v-if="previewUrl">
									<template #icon>
										<ReloadOutlined />
									</template>
									刷新预览
								</a-button>
								<a-button type="primary" @click="regenerateApp" :loading="generating">
									<template #icon>
										<ReloadOutlined />
									</template>
									重新生成
								</a-button>
							</div>
						</div>
					</div>
				</div>
			</div>
		</div>

		<!-- 部署成功弹窗 -->
		<DeploySuccessModal
			v-model:open="deployModalVisible"
			:deploy-url="deployedUrl"
			@visit-site="visitDeployedSite"
		/>

		<!-- 应用详情弹窗 -->
		<AppDetailModal
			v-model:open="appDetailModalVisible"
			:app="appInfo"
			:show-actions="canEdit || isAdmin"
			@edit="editApp"
			@delete="confirmDeleteApp"
		/>
	</div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted, nextTick, computed, watch } from 'vue'
import { useRoute, useRouter, onBeforeRouteLeave } from 'vue-router'
import { message, Modal } from 'ant-design-vue'
import { useLoginUserStore } from '@/stores/useLoginUserStore'
import { useGenerationStore } from '@/stores/useGenerationStore'
import { useAppStatus } from '@/composables/useAppStatus'
import { useVisualEditor } from '@/composables/useVisualEditor'
import {
	getAppVoById,
	deployApp as deployAppApi,
	deleteApp as deleteAppApi,
	deleteAppByAdmin,
	downloadAppCode,
} from '@/api/appController'
import { listAppChatHistory, exportChatHistory as exportChatHistoryApi } from '@/api/chatHistoryController'
import { interruptGenerationTask } from '@/services/appExperienceService'
import ACCESS_ENUM from '@/access/accessEnum'
import '@/assets/simple-tool-call-styles.css'
import {
	ArrowLeftOutlined,
	RocketOutlined,
	ReloadOutlined,
	ExportOutlined,
	InfoCircleOutlined,
	DownloadOutlined,
	SendOutlined,
} from '@ant-design/icons-vue'
import kunkunImg from '@/assets/kunkun.png'
import sadKunkunImg from '@/assets/sad-kunkun.svg'
import { getStaticPreviewUrl, getDeployUrl, API_BASE_URL } from '@/config/env'
import { AppDetailModal, DeploySuccessModal, ChatInput, MessageList } from '@/components/app'
import { getCodeGenTypeText, getCodeGenTypeColor } from '@/constants/codeGenType'

interface Message {
	id?: number // 对话历史ID
	role: 'user' | 'assistant'
	content: string
	timestamp: Date
	isHistoryMessage?: boolean // 标记是否为历史消息
	_updateKey?: number // 强制重新渲染的更新键
}

const route = useRoute()
const router = useRouter()
const loginUserStore = useLoginUserStore()
const generationStore = useGenerationStore()

// 组件引用
const messageListRef = ref<InstanceType<typeof MessageList>>()
const messagesContainer = computed(() => messageListRef.value?.messagesContainer)

// 应用信息
const appInfo = ref<API.AppVO | null>(null)
const appId = computed(() => route.params.id as string)

// 使用统一的状态管理
const { isDeployed, canDeploy, updateFromAppVO, updateDeployStatus, DEPLOY_STATUS } = useAppStatus(appId.value)

// 权限检查
const isOwner = computed(() => {
	if (!appInfo.value || !loginUserStore.loginUser?.id) return false
	return appInfo.value.userId === loginUserStore.loginUser.id
})

// 是否为管理员
const isAdmin = computed(() => loginUserStore.loginUser?.userRole === ACCESS_ENUM.ADMIN)

// 是否可以编辑（只有应用创建者可以编辑）
const canEdit = computed(() => isOwner.value)

// 是否可以下载代码（只有应用创建者或管理员可以下载，且有对话记录）
const canDownload = computed(() => {
	// 需要有对话记录且应用已生成内容
	const hasMessages = messages.value.length >= 2
	// 只有应用创建者或管理员可以下载
	const hasPermission = isOwner.value || isAdmin.value
	return hasMessages && hasPermission
})

// 是否可以部署应用（只有应用创建者可以部署，且用户已登录）
const canDeployApp = computed(() => {
	// 检查用户是否已登录
	const isLoggedIn = !!loginUserStore.loginUser?.id
	// 只有应用创建者可以部署
	const hasPermission = isOwner.value
	// 检查部署状态（不在部署中时才能部署）
	const deployAllowed = canDeploy.value
	return isLoggedIn && hasPermission && deployAllowed
})

// 对话相关
const messages = ref<Message[]>([])
const currentMessage = ref('')
const generating = ref(false)
const isUserScrolling = ref(false) // 用户是否在主动滚动
const autoScrollEnabled = ref(true) // 是否启用自动滚动到底部
const scrollTimeout = ref<number | null>(null)
const programmaticScroll = ref(false) // 标记程序触发的滚动

// 历史消息相关
const loadingHistory = ref(false) // 是否正在加载历史消息
const hasMoreHistory = ref(false) // 是否还有更多历史消息
const lastCreateTime = ref<string | undefined>(undefined) // 游标分页参数

// 中断相关
const currentAbortController = ref<AbortController | null>(null)

// 预览相关
const previewUrl = ref('')
const showPreviewLoading = ref(false) // 控制预览加载动画显示
const previewError = ref(false) // 控制预览错误状态
const previewIframe = ref<HTMLIFrameElement>() // 预览 iframe 引用

// iframe 准备就绪回调
const onIframeReady = () => {
	showPreviewLoading.value = false
}

// 可视化编辑器
const {
	isEditMode,
	selectedElements,
	iframeLoaded,
	enterEditMode,
	exitEditMode,
	clearSelectedElements,
	removeSelectedElement,
	highlightElement,
	getSelectedElementsPrompt,
	handleIframeMessage,
} = useVisualEditor(previewIframe, onIframeReady)

// 监听预览URL变化，重置iframe加载状态
watch(previewUrl, (newUrl, oldUrl) => {
	if (newUrl && newUrl !== oldUrl) {
		iframeLoaded.value = false
		previewError.value = false // 重置错误状态
		// 如果可视化编辑模式开启，退出编辑模式
		if (isEditMode.value) {
			exitEditMode()
		}
	}
})

// 处理元素悬浮
const handleElementHover = (element: any, isHover: boolean) => {
	if (element && element.id) {
		highlightElement(element.id, isHover)
	}
}

// 部署相关
const deploying = ref(false)
const deployModalVisible = ref(false)
const deployedUrl = ref('')

// 下载相关
const downloading = ref(false)

// 应用详情弹窗
const appDetailModalVisible = ref(false)

// 导出相关
const exportLoading = ref(false)

// 加载应用信息
const loadAppInfo = async () => {
	try {
		const res = await getAppVoById({ id: appId.value as any })
		if (res.data.code === 0 && res.data.data) {
			appInfo.value = res.data.data

			// 更新状态管理
			updateFromAppVO(appInfo.value)

			// 先加载历史消息
			await loadChatHistory()

			// 检查应用是否正在生成中，如果是则恢复生成状态
			await checkAndRestoreGeneratingState()

			// 检查是否需要自动发送初始消息
			const hasHistoryMessages = messages.value.length > 0
			const shouldShowPreview = messages.value.length >= 2 || (appInfo.value && isDeployed.value)

			// 设置预览URL：如果有至少2条对话记录，或者应用已部署，则展示预览
			if (shouldShowPreview && appInfo.value.id) {
				const codeGenType = appInfo.value.codeGenType || 'multi_file'
				const staticPreviewUrl = getStaticPreviewUrl(
					codeGenType,
					appInfo.value.id.toString(),
					appInfo.value.userId
				) as string

				// 先设置previewUrl以确保按钮显示，然后异步检查URL可用性
				previewUrl.value = staticPreviewUrl
				setTimeout(async () => {
					try {
						const response = await fetch(staticPreviewUrl, { method: 'HEAD' })
						if (response.ok) {
							// URL可用，清除错误状态
							previewError.value = false
						} else {
							// URL不可用，显示错误状态但保留previewUrl以显示按钮
							previewError.value = true
							showPreviewLoading.value = false
						}
					} catch (error) {
						// 网络错误，显示错误状态但保留previewUrl以显示按钮
						previewError.value = true
						showPreviewLoading.value = false
					}
				}, 100) // 延迟100ms执行，避免阻塞页面初始化
			}

			// 只有在以下条件都满足时才自动发送初始消息：
			// 1. 是自己的应用
			// 2. 没有对话历史
			// 3. 应用有初始提示词
			// 4. 不在生成状态中
			if (isOwner.value && !hasHistoryMessages && appInfo.value.initPrompt && !generating.value) {
				setTimeout(() => {
					sendInitialMessage(appInfo.value!.initPrompt!)
				}, 500)
			}
		} else {
			message.error('获取应用信息失败')
			router.push('/')
		}
	} catch (error) {
		message.error('获取应用信息失败，请稍后重试')
		router.push('/')
	}
}

// 检查并恢复生成状态
const checkAndRestoreGeneratingState = async () => {
	if (!appInfo.value?.id || !isOwner.value) {
		return // 只有应用创建者才需要检查生成状态
	}

	try {
		// 使用状态检查服务检查应用是否正在生成
		const { getApplicationStatus } = await import('@/services/appExperienceService')
		const res = await getApplicationStatus(appInfo.value.id)

		if (res.data.code === 0) {
			const status = res.data.data

			// 如果后端状态显示正在生成，显示提示信息
			if (status === 'GENERATING') {
				generating.value = true

				// 创建一个占位消息表示正在生成
				const lastMessage = messages.value[messages.value.length - 1]
				if (!lastMessage || lastMessage.role !== 'assistant') {
					addMessage('assistant', '🔄 [检测到正在生成中，请等待完成或手动停止...]')
				}
			}
		}
	} catch (error) {
		// 检查失败不影响正常流程
	}
}

// 发送初始消息
const sendInitialMessage = (prompt: string) => {
	addMessage('user', prompt)
	generateResponse(prompt)
}

// 加载聊天历史
const loadChatHistory = async () => {
	try {
		const res = await listAppChatHistory({
			appId: appId.value as any,
			pageSize: 10,
			lastCreateTime: undefined, // 首次加载不传游标
		})

		if (res.data.code === 0 && res.data.data?.records) {
			const historyList = res.data.data.records

			// 转换历史记录为消息格式，按照创建时间升序排列
			const historyMessages: Message[] = historyList
				.sort((a, b) => new Date(a.createTime!).getTime() - new Date(b.createTime!).getTime())
				.map((record) => ({
					id: record.id,
					role: record.messageType === 'user' ? 'user' : 'assistant',
					content: record.message!,
					timestamp: new Date(record.createTime!),
					isHistoryMessage: true,
				}))

			messages.value = historyMessages

			// 检查是否还有更多历史消息
			hasMoreHistory.value = historyList.length === 10
			if (hasMoreHistory.value && historyList.length > 0) {
				// 设置游标为最早的消息时间
				lastCreateTime.value = historyList[historyList.length - 1].createTime
			}

			// 滚动到底部
			nextTick(() => {
				scrollToBottom(true)
			})
		}
	} catch (error) {}
}

// 加载更多历史消息
const loadMoreHistory = async () => {
	if (loadingHistory.value || !hasMoreHistory.value) return

	loadingHistory.value = true

	try {
		const res = await listAppChatHistory({
			appId: appId.value as any,
			pageSize: 10,
			lastCreateTime: lastCreateTime.value,
		})

		if (res.data.code === 0 && res.data.data?.records) {
			const historyList = res.data.data.records

			// 转换历史记录为消息格式，按照创建时间升序排列
			const historyMessages: Message[] = historyList
				.sort((a, b) => new Date(a.createTime!).getTime() - new Date(b.createTime!).getTime())
				.map((record) => ({
					id: record.id,
					role: record.messageType === 'user' ? 'user' : 'assistant',
					content: record.message!,
					timestamp: new Date(record.createTime!),
					isHistoryMessage: true,
				}))

			// 将历史消息插入到消息列表的开头
			messages.value = [...historyMessages, ...messages.value]

			// 检查是否还有更多历史消息
			hasMoreHistory.value = historyList.length === 10
			if (hasMoreHistory.value && historyList.length > 0) {
				// 更新游标为最早的消息时间
				lastCreateTime.value = historyList[historyList.length - 1].createTime
			}
		}
	} catch (error) {
		message.error('加载历史消息失败')
	} finally {
		loadingHistory.value = false
	}
}

// 添加消息
const addMessage = (role: 'user' | 'assistant', content: string) => {
	messages.value.push({
		role,
		content,
		timestamp: new Date(),
		isHistoryMessage: false, // 新消息不是历史消息
	})
	nextTick(() => {
		scrollToBottom()
	})
}

// 处理用户滚动
const handleScroll = () => {
	if (!messagesContainer.value) return

	// 如果是程序触发的滚动，忽略这次事件
	if (programmaticScroll.value) {
		programmaticScroll.value = false
		return
	}

	// 清除之前的定时器
	if (scrollTimeout.value) {
		clearTimeout(scrollTimeout.value)
	}

	// 检查是否滚动到底部（允许5px误差）
	const container = messagesContainer.value
	const isAtBottom = container.scrollTop + container.clientHeight >= container.scrollHeight - 5

	if (isAtBottom) {
		// 用户滚动到底部，启用自动滚动
		autoScrollEnabled.value = true
		isUserScrolling.value = false
	} else {
		// 用户不在底部，说明在主动浏览历史消息
		autoScrollEnabled.value = false
		isUserScrolling.value = true
	}

	// 设置短暂延时，防止滚动事件过于频繁
	scrollTimeout.value = setTimeout(() => {
		isUserScrolling.value = false
	}, 150)
}

// 滚动到底部（智能判断是否需要滚动）
const scrollToBottom = (force = false) => {
	if (!messagesContainer.value) return

	// 如果强制滚动，或者启用了自动滚动且用户没有在主动滚动
	if (force || (autoScrollEnabled.value && !isUserScrolling.value)) {
		nextTick(() => {
			if (messagesContainer.value) {
				// 标记这是程序触发的滚动
				programmaticScroll.value = true
				messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight
			}
		})
	}
}

// 手动滚动到底部
const scrollToBottomManually = () => {
	autoScrollEnabled.value = true
	scrollToBottom(true)
}

// 切换编辑模式
const toggleEditMode = () => {
	if (isEditMode.value) {
		exitEditMode()
	} else {
		enterEditMode()
	}
}

// 发送消息
const sendMessage = async () => {
	const message = currentMessage.value.trim()
	if (!message || generating.value) return

	// 获取选中元素的提示词
	const elementsPrompt = getSelectedElementsPrompt()
	const fullMessage = message + elementsPrompt

	// 显示消息时只显示用户的原始输入，不添加样式标签
	// 这样可以确保实时消息和历史消息的显示效果一致
	addMessage('user', fullMessage)
	currentMessage.value = ''

	// 发送消息后清除选中元素并退出编辑模式
	if (selectedElements.value.length > 0) {
		clearSelectedElements()
	}
	if (isEditMode.value) {
		exitEditMode()
	}

	await generateResponse(fullMessage) // 发送包含完整元素信息的消息给后端
}

// 生成AI回复 - 使用POST + fetch + ReadableStream方式处理SSE流，支持实时流式响应和完整的事件处理
const generateResponse = async (userMessage: string) => {
	generating.value = true
	let aiMessageContent = ''
	let hasCreatedAssistantMessage = false

	try {
		// 构建POST请求参数
		const chatRequest = {
			appId: appId.value,
			message: userMessage,
		}
		const sseUrl = `${API_BASE_URL}/app/chat/gen/code`
		const abortController = new AbortController()
		currentAbortController.value = abortController

		// 发起POST-SSE请求
		const response = await fetch(sseUrl, {
			method: 'POST',
			headers: {
				'Content-Type': 'application/json',
				Accept: 'text/event-stream',
				'Cache-Control': 'no-cache',
				Connection: 'keep-alive',
			},
			body: JSON.stringify(chatRequest),
			credentials: 'include',
			signal: abortController.signal,
		})

		if (!response.ok) {
			throw new Error(`SSE请求失败，HTTP状态码: ${response.status}（${response.statusText}）`)
		}
		if (!response.body) {
			throw new Error('SSE响应体为空，无法接收流数据')
		}

		// 注册到全局状态管理器
		generationStore.startGeneration(appId.value, abortController, true)

		// 处理SSE流数据
		const reader = response.body.getReader()
		const decoder = new TextDecoder('utf-8')
		let streamBuffer = ''

		while (true) {
			const { done, value } = await reader.read()

			if (done) {
				// 流结束，确保最终消息已更新
				if (aiMessageContent && hasCreatedAssistantMessage) {
					updateAssistantMessage(aiMessageContent)
				}
				break
			}

			// 解码数据块并累积到缓冲区
			const decodedChunk = decoder.decode(value, { stream: true })
			streamBuffer += decodedChunk

			// 按SSE标准分割完整事件（双换行符分隔）
			const completeEvents = streamBuffer.split('\n\n')
			streamBuffer = completeEvents.pop() || ''

			// 处理每个完整的SSE事件
			for (const event of completeEvents) {
				if (!event.trim()) continue

				const { eventType, eventData } = parseSseEvent(event)
				switch (eventType) {
					case 'message':
						// 处理消息数据块
						if (eventData) {
							const { dataChunk } = parseBackendData(eventData)
							if (dataChunk) {
								aiMessageContent += dataChunk

								// 创建或更新助手消息
								if (!hasCreatedAssistantMessage) {
									createAssistantMessage(aiMessageContent)
									hasCreatedAssistantMessage = true
								} else {
									updateAssistantMessage(aiMessageContent)
								}

								// 自动滚动到底部
								nextTick(() => scrollToBottom())
							}
						}
						break

					case 'done':
						// 生成完成事件
						generationStore.endGeneration('done')
						cleanupGeneration()
						if (aiMessageContent && hasCreatedAssistantMessage) {
							updateAssistantMessage(aiMessageContent)
						}

						// 延迟更新预览，确保文件写入完成
						setTimeout(() => {
							// 生成完成后直接更新预览URL，不显示加载状态
							updatePreview(false)
						}, 1000)
						return

					case 'business-error':
						// 业务错误事件（如限流、权限等）
						const errorMsg = parseErrorData(eventData) || '生成过程中出现未知错误'
						if (hasCreatedAssistantMessage) {
							updateAssistantMessage(`❌ ${errorMsg}`)
						} else {
							createAssistantMessage(`❌ ${errorMsg}`)
						}
						message.error(errorMsg)
						generationStore.endGeneration('error')
						cleanupGeneration()
						// 后端抛出异常错误时，停止加载并显示哭脸错误状态
						showPreviewLoading.value = false
						previewError.value = true
						return

					default:
						// 忽略未知事件类型
						break
				}
			}
		}
	} catch (error: any) {
		// 检查是否是用户主动中断导致的AbortError
		if (error.name === 'AbortError' || error.message?.includes('aborted')) {
			// 用户主动中断，不显示错误信息，保持已添加的中断提示
			console.log('用户主动中断生成，跳过错误处理')
			return
		}

		// 处理其他网络错误或异常
		const errorMsg = error.message || '网络异常或服务器错误，请稍后重 试'
		if (hasCreatedAssistantMessage) {
			updateAssistantMessage(`❌ 生成中断：${errorMsg}`)
		} else {
			createAssistantMessage(`❌ 生成失败：${errorMsg}`)
		}
		generationStore.endGeneration('error')
		cleanupGeneration()
		message.error(errorMsg)
		// 网络异常或服务器错误时，停止加载并显示哭脸错误状态
		showPreviewLoading.value = false
		previewError.value = true
	}
}

// 解析SSE事件格式,支持标准SSE格式：event: 和 data: 字段
const parseSseEvent = (event: string): { eventType: string; eventData: string } => {
	let eventType = 'message'
	let eventData = ''

	const lines = event.split('\n')
	for (const line of lines) {
		const trimmedLine = line.trimEnd()
		if (trimmedLine.startsWith('event:')) {
			// 解析事件类型
			eventType = trimmedLine.slice(6).trim()
		} else if (trimmedLine.startsWith('data:')) {
			// 解析事件数据
			eventData = trimmedLine.slice(5).trim()
		}
	}

	return { eventType, eventData }
}

// 解析后端返回的数据,从JSON格式中提取'd'字段的内容
const parseBackendData = (eventData: string): { dataChunk: string } => {
	try {
		const parsed = JSON.parse(eventData)
		const dataChunk = String(parsed.d || '')
		return { dataChunk }
	} catch (parseError) {
		// JSON解析失败时，直接返回原始数据
		return { dataChunk: eventData }
	}
}

// 解析业务错误事件数据,提取错误消息内容
const parseErrorData = (eventData: string): string => {
	try {
		const parsed = JSON.parse(eventData)
		return parsed.message || parsed.d || '生成过程中出现错误'
	} catch (parseError) {
		// JSON解析失败时，返回原始数据或默认错误信息
		return eventData || '服务器返回错误信息格式异常'
	}
}

// 创建新的助手消息
const createAssistantMessage = (content: string) => {
	const newMessage: Message = {
		id: Date.now() + Math.random(),
		role: 'assistant',
		content: content,
		timestamp: new Date(),
		isHistoryMessage: false,
	}
	// 强制更新数组以触发Vue响应式更新
	messages.value = [...messages.value, newMessage]
}

// 更新现有助手消息内容
const updateAssistantMessage = (content: string) => {
	const messageList = [...messages.value]
	const lastAssistantMsgIndex = messageList.findLastIndex((msg) => msg.role === 'assistant')

	if (lastAssistantMsgIndex >= 0) {
		// 复制并更新消息，确保触发Vue响应式更新
		messageList[lastAssistantMsgIndex] = {
			...messageList[lastAssistantMsgIndex],
			content: content,
			timestamp: new Date(),
			_updateKey: Date.now(), // 强制更新标识
		}
		messages.value = messageList
	} else {
		// 如果没有找到助手消息，创建新的
		createAssistantMessage(content)
	}
}

// 清理生成状态和资源
const cleanupGeneration = () => {
	if (currentAbortController.value) {
		currentAbortController.value.abort()
		currentAbortController.value = null
	}
	generating.value = false
}

// 用户手动停止AI生成
const stopGeneration = async () => {
	if (!generating.value || !appInfo.value?.id) {
		return
	}

	try {
		// 先在最后一条消息中添加中断提示，避免被abort错误覆盖
		const lastMessage = messages.value[messages.value.length - 1]
		if (lastMessage && lastMessage.role === 'assistant') {
			lastMessage.content += '\n\n🛑 [用户主动停止生成]'
		}

		// 通知全局状态管理器用户主动停止
		generationStore.endGeneration('user_stop')

		// 清理生成状态和资源（这会触发abort）
		cleanupGeneration()

		// 调用后端中断接口
		const res = await interruptGenerationTask(appInfo.value.id!)

		if (res.data.code === 0) {
			message.success('已成功停止生成')
		} else {
			message.warning(`停止请求已发送: ${res.data.message || '请稍等片刻'}`)
		}
	} catch (error) {
		message.error('停止请求发送失败，但本地已停止')
	}
}

// 更新预览URL和加载状态
const updatePreview = (showLoading: boolean = true) => {
	if (appInfo.value?.id) {
		// 重置状态
		showPreviewLoading.value = false
		previewError.value = false

		// 构建预览URL
		const codeGenType = appInfo.value.codeGenType || 'multi_file'
		previewUrl.value = getStaticPreviewUrl(codeGenType, appInfo.value.id.toString(), appInfo.value.userId) as string

		// 根据参数决定是否显示加载状态
		if (showLoading) {
			// 延迟显示加载状态，确保DOM更新
			setTimeout(() => {
				if (appInfo.value?.id) {
					showPreviewLoading.value = true
				}
			}, 50)
		}
	}
}

// 强制刷新预览iframe
const refreshPreview = async () => {
	// 显示加载状态
	showPreviewLoading.value = true
	previewError.value = false

	// 必须显示2秒加载态
	await new Promise((resolve) => setTimeout(resolve, 2000))

	// 如果没有previewUrl，尝试重新构造
	if (!previewUrl.value && appInfo.value?.id) {
		const codeGenType = appInfo.value.codeGenType || 'multi_file'
		previewUrl.value = getStaticPreviewUrl(codeGenType, appInfo.value.id.toString(), appInfo.value.userId) as string
	}

	// 检查必要元素
	if (!previewUrl.value) {
		showPreviewLoading.value = false
		previewError.value = true
		return
	}

	// 构造刷新URL（添加时间戳强制刷新）
	const originalUrl = previewUrl.value.split('?')[0].split('#')[0]
	const timestamp = Date.now()
	const refreshUrl = `${originalUrl}?t=${timestamp}`

	// 使用与loadAppInfo相同的URL检查逻辑
	try {
		const response = await fetch(refreshUrl, { method: 'HEAD' })
		if (response.ok) {
			// URL可用，设置预览URL并清除错误状态
			previewUrl.value = refreshUrl
			previewError.value = false
			showPreviewLoading.value = false
		} else {
			// URL不可用，显示错误状态但保留previewUrl以显示按钮
			previewError.value = true
			showPreviewLoading.value = false
		}
	} catch (error) {
		// 网络错误，显示错误状态但保留previewUrl以显示按钮
		previewError.value = true
		showPreviewLoading.value = false
	}
}

// 新窗口打开
const openInNewWindow = () => {
	if (previewUrl.value) {
		window.open(previewUrl.value, '_blank')
	}
}

// 重新生成应用
const regenerateApp = () => {
	if (generating.value) {
		message.warning('当前正在生成中，请稍后再试')
		return
	}

	// 重置预览状态
	previewError.value = false
	showPreviewLoading.value = false

	// 发送重新生成的消息
	const regenerateMessage = '请重新生成这个应用'
	addMessage('user', regenerateMessage)
	generateResponse(regenerateMessage)
}

// iframe加载完成
const onIframeLoad = (event: Event) => {
	const iframe = event.target as HTMLIFrameElement
	const loadedUrl = iframe.src

	// 检查是否是预期的加载（排除about:blank）
	if (loadedUrl && loadedUrl !== 'about:blank') {
		// 简单处理：iframe能够加载就认为成功
		// 因为URL可访问性已经在refreshPreview中检测过了
		showPreviewLoading.value = false
		previewError.value = false
	}
}

// iframe加载错误
const onIframeError = (event: Event) => {
	// 隐藏加载动画并显示错误状态
	showPreviewLoading.value = false
	previewError.value = true
}

// 下载应用代码
const downloadCode = async () => {
	// 检查是否正在生成，如果是则阻止下载
	if (generating.value) {
		message.warning('当前正在生成内容，请等待生成完成后再下载代码')
		return
	}

	if (!appInfo.value?.id) {
		message.error('应用信息不存在')
		return
	}

	// 权限检查
	if (!canDownload.value) {
		message.error('您没有权限下载此应用的代码，或应用尚未生成内容')
		return
	}

	downloading.value = true

	try {
		// 使用downloadAppCode API，设置responseType为blob以正确处理二进制流
		const response = await downloadAppCode({ appId: appInfo.value.id }, { responseType: 'blob' })

		// 检查HTTP状态码
		if (response.status !== 200) {
			message.error(`请求失败，状态码: ${response.status}`)
			return
		}

		// 检查响应数据类型
		let blob: Blob

		if (response.data instanceof Blob) {
			// 检查Blob内容类型
			if (response.data.type === 'application/zip' || response.data.type === 'application/x-zip-compressed') {
				// 确实是zip文件，下载成功
				blob = response.data
			} else if (response.data.type === 'application/json' || response.data.type.includes('json')) {
				// Blob是JSON格式，说明是错误响应，需要解析
				try {
					const text = await response.data.text()
					const errorData = JSON.parse(text)
					const errorMessage = errorData.message || errorData.description || '下载失败'

					// 特殊处理VIP相关错误
					if (errorMessage.includes('VIP') || errorMessage.includes('下载次数') || errorMessage.includes('权限不足')) {
						message.error(errorMessage + '，请升级VIP或联系管理员')
					} else {
						message.error(errorMessage)
					}
					return
				} catch (parseError) {
					message.error('下载失败，响应解析错误')
					return
				}
			} else {
				// 其他类型的Blob，尝试作为文件处理
				blob = response.data
			}
		} else if (response.data && typeof response.data === 'object') {
			// 如果是普通对象（理论上不应该发生，因为设置了responseType: 'blob'）
			const errorMessage = response.data.message || response.data.description || '下载失败'

			// 特殊处理VIP相关错误
			if (errorMessage.includes('VIP') || errorMessage.includes('下载次数') || errorMessage.includes('权限不足')) {
				message.error(errorMessage + '，请升级VIP或联系管理员')
			} else {
				message.error(errorMessage)
			}
			return
		} else {
			message.error('服务器返回数据格式异常')
			return
		}

		// 验证blob
		if (!blob || !(blob instanceof Blob)) {
			message.error('文件数据不存在或格式错误')
			return
		}

		// 获取文件名
		let filename = `${appInfo.value.appName || 'app'}_源码_${Date.now()}.zip`

		// 从响应头中获取文件名（如果有）
		const contentDisposition = response.headers['content-disposition']
		if (contentDisposition) {
			// 后端格式：attachment; filename="project.zip"; filename*=UTF-8''encodedFileName
			// 优先尝试解析 filename* 参数（支持UTF-8编码）
			const filenameStarMatch = contentDisposition.match(/filename\*=UTF-8''([^;]+)/)
			if (filenameStarMatch && filenameStarMatch[1]) {
				try {
					filename = decodeURIComponent(filenameStarMatch[1])
				} catch (e) {}
			} else {
				// 回退到普通filename参数
				const filenameMatch = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/)
				if (filenameMatch && filenameMatch[1]) {
					filename = filenameMatch[1].replace(/['"]/g, '')
				}
			}
		}

		// 创建下载链接
		const url = window.URL.createObjectURL(blob)
		const link = document.createElement('a')
		link.href = url
		link.download = filename

		// 触发下载
		document.body.appendChild(link)
		link.click()

		// 清理
		document.body.removeChild(link)
		window.URL.revokeObjectURL(url)

		message.success('代码下载成功！')
	} catch (error: any) {
		// 详细的错误处理
		if (error.response) {
			// 服务器响应了错误状态码
			const status = error.response.status
			const errorData = error.response.data

			if (status === 401) {
				message.error('登录已过期，请重新登录')
			} else if (status === 403) {
				message.error('没有权限下载此应用代码')
			} else if (status === 404) {
				message.error('应用不存在或代码文件未找到')
			} else if (status >= 500) {
				message.error('服务器内部错误，请稍后重试')
			} else if (errorData && typeof errorData === 'object') {
				// 尝试解析后端返回的错误信息（BusinessException格式）
				const errorMessage = errorData.message || errorData.description || errorData.error || `请求失败 (${status})`
				message.error(errorMessage)
			} else {
				message.error(`请求失败，状态码: ${status}`)
			}
		} else if (error.request) {
			// 请求已发送但没有收到响应
			message.error('网络连接失败，请检查网络连接')
		} else {
			// 其他错误
			const errorMessage = error.message || '下载失败，未知错误'
			message.error(errorMessage)
		}
	} finally {
		downloading.value = false
	}
}

// 部署应用
const deployApp = async () => {
	// 【新增】检查是否正在生成，如果是则阻止部署
	if (generating.value) {
		message.warning('当前正在生成内容，请等待生成完成后再部署应用')
		return
	}

	if (!appInfo.value?.id) return

	deploying.value = true
	// 更新状态为部署中
	updateDeployStatus(DEPLOY_STATUS.DEPLOYING)

	try {
		const res = await deployAppApi({ appId: appInfo.value.id })
		if (res.data.code === 0 && res.data.data) {
			// 后端直接返回完整的部署URL
			const deployKey = res.data.data
			// 直接使用后端返回的URL作为部署地址
			deployedUrl.value = deployKey
			deployModalVisible.value = true
			message.success('应用部署成功！')

			// 更新状态为已部署，并设置部署密钥
			updateDeployStatus(DEPLOY_STATUS.DEPLOYED, deployKey, new Date().toISOString())

			// 同步更新appInfo
			if (appInfo.value) {
				appInfo.value.deployStatus = DEPLOY_STATUS.DEPLOYED
				appInfo.value.deployKey = deployKey
				appInfo.value.deployedTime = new Date().toISOString()
			}
		} else {
			message.error('部署失败：' + (res.data.message || '未知错误'))
			// 部署失败，恢复为未部署状态
			updateDeployStatus(DEPLOY_STATUS.NOT_DEPLOYED)
		}
	} catch (error) {
		message.error('部署失败，请稍后重试')
		// 部署失败，恢复为未部署状态
		updateDeployStatus(DEPLOY_STATUS.NOT_DEPLOYED)
	} finally {
		deploying.value = false
	}
}

// 访问部署的网站
const visitDeployedSite = () => {
	if (deployedUrl.value) {
		window.open(deployedUrl.value, '_blank')
	}
}

// 显示应用详情弹窗
const showAppDetailModal = () => {
	// 【新增】检查是否正在生成，如果是则提示用户
	if (generating.value) {
		message.info('当前正在生成内容，详情信息可能不是最新状态。建议等待生成完成后查看。')
	}

	appDetailModalVisible.value = true
}

// 导出对话历史
const exportChatHistory = async () => {
	// 【新增】检查是否正在生成，如果是则阻止导出
	if (generating.value) {
		message.warning('当前正在生成内容，请等待生成完成后再导出对话历史')
		return
	}

	if (!appInfo.value?.id || messages.value.length === 0) {
		message.warning('暂无对话历史可导出')
		return
	}

	// 权限检查
	if (!canEdit.value && !isAdmin.value) {
		message.error('您没有权限导出此应用的对话历史')
		return
	}

	exportLoading.value = true
	try {
		// 使用导出API
		const response: any = await exportChatHistoryApi({ appId: appInfo.value.id })

		// 检查HTTP状态码
		if (response.status !== 200) {
			message.error(`请求失败，状态码: ${response.status}`)
			return
		}

		// 检查响应数据
		let content: string

		if (typeof response.data === 'string') {
			// 直接返回字符串内容（成功情况）
			content = response.data
		} else if (response.data && typeof response.data === 'object') {
			// 返回JSON对象，说明后端返回了错误信息（BusinessException被全局异常处理器处理）
			const errorMessage = response.data.message || response.data.description || response.data.error || '导出失败'

			// 特殊处理VIP相关错误
			if (errorMessage.includes('VIP') || errorMessage.includes('导出次数') || errorMessage.includes('权限不足')) {
				message.error(errorMessage + '，请升级VIP或联系管理员')
			} else {
				message.error(errorMessage)
			}
			return
		} else {
			message.error('服务器返回数据格式异常')
			return
		}

		// 验证内容
		if (!content || typeof content !== 'string') {
			message.error('导出内容为空或格式错误')
			return
		}

		// 创建文件名
		const fileName = `对话历史_${appInfo.value.appName || 'app'}_${Date.now()}.md`

		// 创建Blob和下载链接
		const blob = new Blob([content], { type: 'text/markdown;charset=utf-8' })
		const url = window.URL.createObjectURL(blob)
		const link = document.createElement('a')
		link.href = url
		link.download = fileName
		document.body.appendChild(link)
		link.click()

		// 清理
		window.URL.revokeObjectURL(url)
		document.body.removeChild(link)

		message.success('对话历史导出成功')
	} catch (error: any) {
		// 详细的错误处理
		if (error.response) {
			// 服务器响应了错误状态码
			const status = error.response.status
			const errorData = error.response.data

			if (status === 401) {
				message.error('登录已过期，请重新登录')
			} else if (status === 403) {
				message.error('没有权限导出此应用的对话历史')
			} else if (status === 404) {
				message.error('应用不存在或对话历史未找到')
			} else if (status >= 500) {
				message.error('服务器内部错误，请稍后重试')
			} else if (errorData && typeof errorData === 'object') {
				// 尝试解析后端返回的错误信息（BusinessException格式）
				const errorMessage = errorData.message || errorData.description || errorData.error || `请求失败 (${status})`
				message.error(errorMessage)
			} else {
				message.error(`请求失败，状态码: ${status}`)
			}
		} else if (error.request) {
			// 请求已发送但没有收到响应
			message.error('网络连接失败，请检查网络连接')
		} else {
			// 其他错误
			const errorMessage = error.message || '导出失败，未知错误'
			message.error(errorMessage)
		}
	} finally {
		exportLoading.value = false
	}
}

// 编辑应用
const editApp = () => {
	if (appInfo.value?.id) {
		// 在新窗口中打开编辑页面，避免影响当前生成状态和SSE连接
		const editUrl = `${window.location.origin}/app/edit/${appInfo.value.id}`
		window.open(editUrl, '_blank')

		// 【修改】根据生成状态提供不同的提示
		if (generating.value) {
			message.info('编辑页面已在新窗口打开。注意：当前正在生成内容，建议等待生成完成后再进行编辑操作。')
		} else {
			message.info('编辑页面已在新窗口打开')
		}
	}
}

// 确认删除应用
const confirmDeleteApp = () => {
	if (!appInfo.value?.id) return

	Modal.confirm({
		title: '确认删除',
		content: `确定要删除应用"${appInfo.value.appName}"吗？此操作不可撤销。`,
		okText: '确认删除',
		okType: 'danger',
		cancelText: '取消',
		async onOk() {
			await deleteApp()
		},
	})
}

// 删除应用
const deleteApp = async () => {
	if (!appInfo.value?.id) return

	const hideLoading = message.loading('正在删除应用...', 0)
	try {
		const isAdmin = loginUserStore.loginUser?.userRole === ACCESS_ENUM.ADMIN
		let res

		if (isAdmin) {
			// 管理员删除
			res = await deleteAppByAdmin({ id: appInfo.value.id })
		} else {
			// 普通用户删除
			res = await deleteAppApi({ id: appInfo.value.id })
		}

		if (res.data.code === 0) {
			hideLoading()
			message.success('删除成功')
			// 删除成功后跳转回首页
			router.push('/')
		} else {
			hideLoading()
			message.error('删除失败：' + (res.data.message || '未知错误'))
		}
	} catch (error) {
		hideLoading()
		console.error('删除应用失败:', error)
		message.error('删除失败，请稍后重试')
	}
}

// 返回
const goBack = () => {
	router.push('/')
}

// 组件卸载时清理资源（但不强制停止生成）
onUnmounted(() => {
	// 【修正】不自动清理生成状态，让SSE连接可能在后台继续
	// 只清理UI相关的事件监听器
	if (scrollTimeout.value) {
		clearTimeout(scrollTimeout.value)
	}

	// 移除浏览器页面关闭前事件监听
	window.removeEventListener('beforeunload', handleBeforeUnload)
})

// 路由离开前确认（但不强制停止）
onBeforeRouteLeave((to, from, next) => {
	// 如果正在生成，提醒用户但不强制停止
	if (generating.value) {
		Modal.confirm({
			title: '当前正在生成内容',
			content: '检测到正在生成AI内容，离开页面后生成会在后台继续。您可以稍后返回查看结果，或者手动停止生成。',
			okText: '离开页面',
			cancelText: '留在当前页',
			okType: 'primary', // 改为primary，不是danger
			onOk() {
				// 【修正】不清理生成状态，让生成在后台继续

				next()
			},
			onCancel() {
				next(false)
			},
		})
	} else {
		next()
	}
})

// 浏览器页面关闭前确认（但不强制停止）
const handleBeforeUnload = (event: BeforeUnloadEvent) => {
	if (generating.value) {
		const message = '当前正在生成AI内容，关闭页面后生成会继续在后台进行。'
		event.preventDefault()
		event.returnValue = message
		return message
	}
}

// 组件挂载时加载应用信息
onMounted(() => {
	loadAppInfo()
	// 监听浏览器页面关闭前事件
	window.addEventListener('beforeunload', handleBeforeUnload)

	// 初始化滚动状态
	nextTick(() => {
		// 确保初始时处于底部并启用自动滚动
		autoScrollEnabled.value = true
		scrollToBottom(true)
	})
})
</script>

<style scoped lang="scss">
#app-chat-view {
	height: 100vh; // 现在导航栏隐藏了，可以使用全屏高度
	display: flex;
	flex-direction: column;

	.header-bar {
		background: white;
		padding: 16px 24px; // 增加左右内边距
		border-bottom: 1px solid #e8e8e8;
		display: flex;
		justify-content: space-between;
		align-items: center;
		box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);

		.header-left {
			display: flex;
			align-items: center;
			gap: 16px;

			.back-btn {
				color: #666;

				&:hover {
					color: #1890ff;
				}
			}

			.header-logo {
				height: 48px;
				width: auto;
				object-fit: contain;
			}

			.app-name {
				margin: 0;
				font-size: 20px;
				font-weight: 600;
				color: #2d3748;
				white-space: nowrap;
				overflow: hidden;
				text-overflow: ellipsis;
				max-width: 300px;
			}

			.code-gen-type-tag {
				font-size: 12px;
				padding: 4px 8px;
				border-radius: 4px;
				font-weight: 500;
			}
		}

		.header-right {
			display: flex;
			gap: 12px;

			.detail-btn {
				height: 40px;
				padding: 0 20px;
				border: 1px solid #d9d9d9;
				border-radius: 6px;

				&:hover {
					border-color: #40a9ff;
					color: #40a9ff;
				}
			}

			.download-btn {
				background: linear-gradient(135deg, #52c41a 0%, #389e0d 100%);
				border: none;
				height: 40px;
				padding: 0 24px;
				color: white;
				margin-right: 12px;

				&:hover:not(:disabled) {
					transform: translateY(-1px);
					box-shadow: 0 4px 12px rgba(82, 196, 26, 0.3);
					background: linear-gradient(135deg, #73d13d 0%, #52c41a 100%);
				}

				&:disabled {
					opacity: 0.6;
					background: #d9d9d9;
					color: rgba(0, 0, 0, 0.25);
				}
			}

			.deploy-btn {
				background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
				border: none;
				height: 40px;
				padding: 0 24px;

				&:hover:not(:disabled) {
					transform: translateY(-1px);
					box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
				}

				&:disabled {
					opacity: 0.6;
				}
			}
		}
	}

	.content-area {
		flex: 1;
		display: flex;
		gap: 20px; // 增加左右区域间的间隔
		padding: 20px 24px; // 添加整体内边距
		overflow: hidden;
		background: #f8fafc; // 添加浅色背景区分

		.chat-section {
			width: 50%; /* 固定宽度，防止布局变化 */
			min-width: 400px; /* 最小宽度保证可用性 */
			flex-shrink: 0; /* 防止收缩 */
			background: white;
			border-radius: 12px; // 添加圆角
			box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04); // 添加阴影
			display: flex;
			flex-direction: column;
		}

		.preview-section {
			width: 50%; /* 固定宽度，与聊天区域对称 */
			min-width: 400px;
			flex-shrink: 0; /* 防止收缩 */
			background: white;
			display: flex;
			flex-direction: column;
			border-radius: 12px;
			box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
			margin-right: 24px;

			.preview-header {
				padding: 20px 24px;
				border-bottom: 1px solid #e8e8e8;
				display: flex;
				justify-content: space-between;
				align-items: center;

				h3 {
					margin: 0;
					font-size: 16px;
					font-weight: 600;
				}

				.preview-actions {
					display: flex;
					gap: 8px;
				}
			}

			.preview-content {
				flex: 1;
				position: relative;
				padding: 24px;

				.ai-loading-overlay {
					position: absolute;
					top: 0;
					left: 0;
					right: 0;
					bottom: 0;
					background: rgba(255, 255, 255, 0.95);
					backdrop-filter: blur(2px);
					display: flex;
					align-items: center;
					justify-content: center;
					z-index: 10;

					.loading-content {
						text-align: center;

						.loading-kunkun {
							width: 100px;
							height: 100px;
							object-fit: contain;
							animation: spin 2s linear infinite;
							margin-bottom: 20px;
						}

						.loading-text {
							font-size: 16px;
							color: #666;
							font-weight: 500;
							animation: pulse 1.5s ease-in-out infinite;
						}
					}
				}

				.preview-iframe {
					width: 100%;
					height: 100%;
					border: none;
					background: white;
				}

				.preview-error {
					height: 100%;
					display: flex;
					align-items: center;
					justify-content: center;

					.error-content {
						text-align: center;
						color: #666;
						max-width: 300px;

						.error-kunkun {
							width: 120px;
							height: 120px;
							margin-bottom: 20px;
							opacity: 0.9;
						}

						h4 {
							margin: 0 0 12px 0;
							font-size: 18px;
							color: #ff6b6b;
							font-weight: 600;
						}

						p {
							margin: 0 0 24px 0;
							font-size: 14px;
							line-height: 1.6;
							color: #999;
						}

						.error-actions {
							display: flex;
							gap: 12px;
							justify-content: center;
							flex-wrap: wrap;

							.ant-btn {
								border-radius: 6px;
								height: 36px;
								padding: 0 16px;
								font-size: 14px;

								&.ant-btn-primary {
									background: linear-gradient(135deg, #ff6b6b 0%, #ee5a52 100%);
									border: none;

									&:hover:not(:disabled) {
										background: linear-gradient(135deg, #ff8a80 0%, #ff6b6b 100%);
										transform: translateY(-1px);
										box-shadow: 0 4px 12px rgba(255, 107, 107, 0.3);
									}
								}

								&:not(.ant-btn-primary) {
									border-color: #d9d9d9;
									color: #666;

									&:hover {
										border-color: #40a9ff;
										color: #40a9ff;
									}
								}
							}
						}
					}
				}

				.preview-placeholder {
					height: 100%;
					display: flex;
					align-items: center;
					justify-content: center;
				}
			}
		}
	}

	.deploy-success-modal {
		:deep(.ant-modal-content) {
			border-radius: 12px;
		}

		.deploy-success-content {
			text-align: center;
			padding: 20px;

			.success-icon {
				font-size: 48px;
				color: #52c41a;
				margin-bottom: 16px;
			}

			h3 {
				font-size: 20px;
				margin-bottom: 12px;
				color: #2d3748;
			}

			p {
				color: #666;
				margin-bottom: 20px;
				line-height: 1.6;
			}

			.url-input {
				text-align: left;
			}

			// 添加悬停效果
			:deep(.ant-btn-primary:hover) {
				background: linear-gradient(135deg, #40a9ff, #1890ff) !important;
				box-shadow: 0 5px 16px rgba(24, 144, 255, 0.45) !important;
				transform: translateY(-2px) !important;
				transition: all 0.25s ease !important;
			}

			:deep(.ant-btn:not(.ant-btn-primary):hover) {
				border-color: #1890ff !important;
				color: #1890ff !important;
				background: #f8fbff !important;
			}
		}
	}

	.app-detail-modal {
		:deep(.ant-modal-content) {
			border-radius: 12px;
		}

		.app-detail-content {
			.app-basic-info {
				margin-bottom: 32px !important;
				padding-bottom: 16px;

				h4 {
					font-size: 16px;
					font-weight: 600;
					color: #2d3748;
					margin-bottom: 16px;
					padding-bottom: 8px;
					border-bottom: 1px solid #e8e8e8;
				}

				.info-label {
					color: #666;
					font-weight: 500;
					text-align: left;
				}

				.creator-content {
					display: flex !important;
					align-items: center !important;
					gap: 12px !important;

					.creator-name {
						font-weight: 500;
						color: #2d3748;
						margin-left: 0 !important;
					}
				}

				.time-value {
					color: #2d3748;
				}
			}

			.app-actions-section {
				margin-top: 32px !important;
				padding-top: 16px !important;
				border-top: 1px solid #f0f0f0 !important;
			}

			// 确保Ant Design的Row组件也有合适的间距
			:deep(.app-actions-section .ant-row) {
				margin-top: 0 !important;
			}
		}
	}
}

@media (max-width: 768px) {
	#app-chat-view {
		.header-bar {
			padding: 12px 20px;

			.header-left {
				.header-logo {
					height: 36px; // 移动端logo稍小一些
				}

				.app-name {
					font-size: 16px;
				}
			}

			.header-right {
				.download-btn {
					padding: 0 12px;
					font-size: 14px;
					margin-right: 8px;
				}

				.deploy-btn {
					padding: 0 16px;
					font-size: 14px;
				}
			}
		}

		.content-area {
			flex-direction: column;
			padding: 16px 20px;
			gap: 16px;

			.chat-section {
				height: 50%;
				min-height: 400px;
				margin-right: 0;
				padding: 20px;
			}

			.preview-section {
				height: 50%;
				min-height: 300px;
				margin-right: 0;

				.preview-header {
					padding: 16px 20px;
				}

				.preview-content {
					padding: 20px;
				}
			}
		}
	}
}

// 动画关键帧
@keyframes spin {
	from {
		transform: rotate(0deg);
	}
	to {
		transform: rotate(360deg);
	}
}

@keyframes pulse {
	0%,
	100% {
		opacity: 0.7;
	}
	50% {
		opacity: 1;
	}
}

@keyframes fadeInUp {
	from {
		opacity: 0;
		transform: translateY(10px);
	}
	to {
		opacity: 1;
		transform: translateY(0);
	}
}
</style>
